package com.octopus.object;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.apache.log4j.Logger;

import com.octopus.string.StringUtils;

public class ObjectUtils {
	
	private final static String nullObjectString = "$NULL[$NULL]";
	
	private final static Logger logger = Logger.getLogger(ObjectUtils.class.getName());
	
	public static final Object cloneCloneImpObject(Object object) {
		if (object == null) {
			return null;
		}
		Method cloneMethod = null;
		try {
			cloneMethod = object.getClass().getMethod("clone", new Class[]{});
		} catch (SecurityException e) {
			logger.error(e);
		} catch (NoSuchMethodException e) {
			logger.error(e);
		}
		if (cloneMethod == null) {
			return null;
		}

		Object newCloneObject = null;

		if (Modifier.isPublic(cloneMethod.getModifiers())) {
			try {
				newCloneObject = cloneMethod.invoke(object, (Object[]) null);
			} catch (IllegalArgumentException e) {
				logger.error(e);
			} catch (IllegalAccessException e) {
				logger.error(e);
			} catch (InvocationTargetException e) {
				logger.error(e);
			}
		}
		return newCloneObject;
	}

	public static final Object byteClone(Object src) {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(baos);
			out.writeObject(src);
			out.close();
			ByteArrayInputStream bin = new ByteArrayInputStream(
					baos.toByteArray());
			ObjectInputStream in = new ObjectInputStream(bin);
			Object clone = in.readObject();
			in.close();
			return (clone);
		} catch (ClassNotFoundException e) {
			logger.error(e);
		} catch (StreamCorruptedException e) {
			logger.error(e);
		} catch (IOException e) {
			logger.error(e);
		}
		return null;
	}
	
	public static final String asString(Object object) {
		if(object == null){
			return nullObjectString;
		}
		if(!(object instanceof java.io.Serializable)){
			return nullObjectString;
		}
		synchronized(object){
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream oos = null;
			try{
				oos = new ObjectOutputStream(baos);
				oos.writeObject(object);
			}catch(IOException ioe){
				//logger.fatal(StringUtils.concat("asString class[",object.getClass().getName(),"]"), ioe);
				return nullObjectString;
			}finally{
				if(baos != null){
					try {baos.close();} catch (IOException e) {}
				}
				if(oos != null){
					try{oos.close();}catch(IOException e){}
				}
			}
			try{
				return StringUtils.base64en(baos.toByteArray());
			}catch(UnsupportedEncodingException uee){
				logger.fatal("asString StringUtils.base64en", uee);
			}
			return null;
		}
	}

	public static final Object asObject(String string) {
		if(string == null){
			return null;
		}
		if(StringUtils.stringEquals(string, nullObjectString)){
			return null;
		}
		
		ByteArrayInputStream bais = null;
		ObjectInputStream ois = null;
		try {
			bais = new ByteArrayInputStream(StringUtils.base64de(string));
			ois = new ObjectInputStream(bais);
			Object object = ois.readObject();
			return object;
		} catch (UnsupportedEncodingException e) {
			logger.fatal("asObject StringUtils.base64de", e);
		} catch (IOException e) {
			logger.fatal("asObject class", e);
		} catch (ClassNotFoundException e) {
			logger.fatal("asObject readObject", e);
		} finally {
			if(ois != null){
				try{ois.close();}catch(Exception e){};
			}
			if(bais != null){
				try{bais.close();}catch(Exception e){};
			}
		}
		return null;
	}
}
